-- skywalking
skywalking_tracer:start("upstream service")
-- 租户编码
local tenant_code = nil
local redis_instance = nil
-- 请求url路径，获取"/api/应用名/" 或 "/basic-api/" 之后的路径
local uri = ngx.var.request_uri
local i, j = string.find(uri, "/", 2)
local uri_pre = string.sub(uri, 2, j - 1)
uri = string.sub(uri, j)
if uri_pre == "api" then
    i , j = string.find(uri, "/", 2)
    uri = string.sub(uri, j)
end

-- 关闭redis连接
local function close_redis(redis_instance)
    -- redis-cluster没有close方法
    if not (redis_instance and redis_instance['close']) then
        return
    end
    local ok, err = redis_instance:close()
    if not ok then
        ngx.log(ngx.ERR, "close redis error : " .. err)
    end
end

--[[
    以指定分割符对字符串进行分割
    可用于分割Redis集群的地址列表，或单个地址的IP与端口
    full_str: 要分割的字符串;
    separator: 分割符;
    skip_empty: 是否跳过空元素,即分割符连续出现是否视为一次,默认否;
    split_count: 最大分割次数,默认全部分割,只能为-1或正整数.
    ]]
local function str_split(full_str, separator, skip_empty, split_count)
    -- 默认全部分割
    if not split_count or split_count == -1 then
        split_count = -1
    else
        if split_count < 1 then
            ngx.log(ngx.ERR, "max split count error.")
        end
    end
    local split_array = {}
    local start_idx = 1
    local end_idx

    repeat
        end_idx = string.find(full_str, separator, start_idx, true)
        if end_idx == start_idx and skip_empty then
            goto empty_element
        end
        table.insert(split_array, string.sub(full_str, start_idx, end_idx and end_idx - 1 or -1))
        :: empty_element ::
        start_idx = end_idx and end_idx + #separator
    until #split_array == split_count or not end_idx

    return split_array
end

-- 初始化redis
local function init_redis()
    -- 获取环境变量
    local redis_props = {
        server = os.getenv("REDIS_SERVER"),
        auth = os.getenv("REDIS_PASSWORD"),
        connect_timeout = 1000
    }

    -- 获取redis连接信息
    local serv_list = str_split(redis_props.server, ",")

    -- 有多个server，使用集群版连接
    if #serv_list ~= 1 then
        local cluster_serv = {}
        for index, value in pairs(serv_list) do
            local serv_item = str_split(value, ":")
            cluster_serv[index] = { ip = serv_item[1], port = serv_item[2] }
        end
        redis_props['serv_list'] = cluster_serv
        redis_props['server'] = nil
        -- 使用redis-cluster模块的必填参数
        redis_props['name'] = 'redisCluster'
        local redis_cluster = require("resty.rediscluster")
        redis_instance = redis_cluster:new(redis_props)
    else
        -- 只有一个server，使用单机版连接
        local host_port = str_split(serv_list[1], ":")
        local redis = require("resty.redis")
        redis_instance = redis:new()

        redis_instance:set_timeout(redis_props['connect_timeout'])
        local ok, err = redis_instance:connect(host_port[1], host_port[2])
        if not ok then
            ngx.log(ngx.ERR, "failed to connect:" .. err)
            return close_redis(redis_instance)
        end

        local auth, err = redis_instance:auth(redis_props['auth'])
        if not auth then
            ngx.log(ngx.ERR, "failed to authenticate : " .. err)
            return close_redis(redis_instance)
        end

        -- 切换库
        local db_number = os.getenv("REDIS_DATABASE")
        if db_number and db_number ~= 0 then
            redis_instance:select(db_number)
        end
    end

end



-- 获取租户编码
local function init_tenant_code()
    -- 从请求头中获取租户编码
    tenant_code = ngx.req.get_headers()["tenantCode"]
    if tenant_code ~= nil and #tenant_code > 0 then
        return
    end

    -- 从redis中获取域名对应的租户编码
    local domainName = ngx.req.get_headers()["Host"]
    init_redis()
    local tenant, err = redis_instance:hget("saaslanding:domain:tenant", domainName)
    if type(tenant) == 'userdata' then
        ngx.log(ngx.ERR, "get redis key null(userdata)")
        return close_redis(redis_instance)
    end
    if not tenant then
        ngx.log(ngx.ERR, "get redis key error : " .. err)
        return close_redis(redis_instance)
    end
    -- 租户code存到请求头
    ngx.req.set_header("tenant", tenant)
    tenant_code = tenant

    -- 从GET请求url中的参数tenant获取
    local ssoLogin = string.match(uri, 'ssoLogin')
    if "GET" == method and ssoLogin ~= nil then
        if tenant_code == nil or #tenant_code == 0 then
            local params = ngx.req.get_uri_args()
            for key, value in pairs(params) do
                if key == "tenant" then
                    tenant_code = value
                    break
                end
            end
        end
    end

end

-- 获取租户编码
init_tenant_code()
-- 租户编码为空，直接走平台侧网关
if tenant_code == nil or #tenant_code == 0 then
    ngx.var.proxy_pass = ngx.var.proxy_pass .. uri
    return
end

if redis_instance == nil then
    init_redis()
end
-- 从redis中获取host
local host, err = redis_instance:hget("saaslanding:gateway:host", tenant_code)
if not host then
    ngx.log(ngx.ERR, "get redis key error : " .. err)
    return close_redis(redis_instance)
end

-- 使用平台侧网关
if host == ngx.null then
    ngx.var.proxy_pass = ngx.var.proxy_pass .. uri
    return close_redis(redis_instance)
end

ngx.var.proxy_pass = host .. uri
close_redis(redis_instance)